package com.ruoyi.system.service.impl;

import java.util.Date;
import java.util.List;

import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.SysSerialRuleMapper;
import com.ruoyi.system.domain.SysSerialRule;
import com.ruoyi.system.service.ISysSerialRuleService;

/**
 * 单据规则Service业务层处理
 * 
 * @author huikai
 * @date 2025-03-13
 */
@Service
public class SysSerialRuleServiceImpl implements ISysSerialRuleService 
{
    private static final Logger log = LoggerFactory.getLogger(SysSerialRuleServiceImpl.class);

    @Autowired
    private SysSerialRuleMapper sysSerialRuleMapper;

    @Autowired
    private RedisCache redisCache;

    private static final String RULE_CACHE_KEY = "sys_serial_rule";
    private static final Integer RULE_CACHE_NUM = 500;

    /**
     * 查询单据规则
     * 
     * @param ruleId 单据规则主键
     * @return 单据规则
     */
    @Override
    public SysSerialRule selectSysSerialRuleByRuleId(Long ruleId)
    {
        return sysSerialRuleMapper.selectSysSerialRuleByRuleId(ruleId);
    }

    /**
     * 查询单据规则
     *
     * @param ruleCode 单据规则编码
     * @return 单据规则
     */
    @Override
    public SysSerialRule selectSysSerialRuleByRuleCode(String ruleCode)
    {
        return sysSerialRuleMapper.selectSysSerialRuleByRuleCode(ruleCode);
    }

    /**
     * 查询单据规则列表
     * 
     * @param sysSerialRule 单据规则
     * @return 单据规则
     */
    @Override
    public List<SysSerialRule> selectSysSerialRuleList(SysSerialRule sysSerialRule)
    {
        return sysSerialRuleMapper.selectSysSerialRuleList(sysSerialRule);
    }

    /**
     * 新增单据规则
     * 
     * @param sysSerialRule 单据规则
     * @return 结果
     */
    @Override
    public int insertSysSerialRule(SysSerialRule sysSerialRule)
    {
        sysSerialRule.setCreateTime(DateUtils.getNowDate());
        return sysSerialRuleMapper.insertSysSerialRule(sysSerialRule);
    }

    /**
     * 修改单据规则
     * 
     * @param sysSerialRule 单据规则
     * @return 结果
     */
    @Override
    public int updateSysSerialRule(SysSerialRule sysSerialRule)
    {
        sysSerialRule.setUpdateTime(DateUtils.getNowDate());
        return sysSerialRuleMapper.updateSysSerialRule(sysSerialRule);
    }

    /**
     * 批量删除单据规则
     * 
     * @param ruleIds 需要删除的单据规则主键
     * @return 结果
     */
    @Override
    public int deleteSysSerialRuleByRuleIds(Long[] ruleIds)
    {
        return sysSerialRuleMapper.deleteSysSerialRuleByRuleIds(ruleIds);
    }

    /**
     * 删除单据规则信息
     * 
     * @param ruleId 单据规则主键
     * @return 结果
     */
    @Override
    public int deleteSysSerialRuleByRuleId(Long ruleId)
    {
        return sysSerialRuleMapper.deleteSysSerialRuleByRuleId(ruleId);
    }

    /**
     * 基于Redis生成唯一的单号
     *
     * @param ruleCode 单据规则主键
     * @return 生成的单号
     */
    public String generateSerialNumber(String ruleCode) {
        String currentKey = StringUtils.toRootLowerCase( "serial:rule:" + ruleCode + ":current");
        Long currentSerialNumber = redisCache.increment(currentKey);

        SysSerialRule rule;
        boolean updateDb = false;
        boolean updateRedis = false;
        if (currentSerialNumber == null) {
            // 如果Redis中没有该规则的序列号，从数据库中获取
            rule = selectSysSerialRuleByRuleCode(ruleCode);
            if (rule == null) {
                throw new RuntimeException("未找到单号生成规则: " + ruleCode);
            }
            //定义当前初始序列号
            currentSerialNumber = rule.getCurrentSeq() == null ? 1L : rule.getCurrentSeq();
            //更新缓存序列号
            rule.setCurrentSeq(currentSerialNumber + RULE_CACHE_NUM);
            //把序列插入redis
            redisCache.setCacheObject(currentKey, Math.toIntExact(currentSerialNumber));

            updateDb = true;
            updateRedis = true;
        } else{
            rule = redisCache.getCacheMapValue(RULE_CACHE_KEY,ruleCode);
            if(rule == null){
                rule = selectSysSerialRuleByRuleCode(ruleCode);
                if (rule == null) {
                    throw new RuntimeException("未找到单号生成规则: " + ruleCode);
                }
            }
        }
        String currentDate = DateUtils.parseDateToStr(rule.getDateFormat(),new Date());
        //日期切换从头开始
        if(!StringUtils.equals(rule.getCurrentDateStr(),currentDate)){
            rule.setCurrentDateStr(currentDate);
            rule.setCurrentSeq(Long.valueOf(RULE_CACHE_NUM));
            currentSerialNumber = 1L;
            //重新起始
            redisCache.setCacheObject(currentKey, Math.toIntExact(currentSerialNumber));
            updateDb = true;
            updateRedis = true;
        }
        //到达缓存最大值，从数据库中获取
        else if(rule.getCurrentSeq() <= currentSerialNumber){
            rule.setCurrentSeq(rule.getCurrentSeq() + RULE_CACHE_NUM);
            updateDb = true;
            updateRedis = true;
        }
        if(updateRedis){
            redisCache.setCacheMapValue(RULE_CACHE_KEY, ruleCode, rule);
        }
        if(updateDb){
            rule.setLastResetTime(new Date());
            updateSysSerialRule(rule);
        }

        // 组合最终的单号
        return  rule.getPrefix() + currentDate + String.format("%0" + rule.getSeqLength() + "d", currentSerialNumber);
    }
}
